`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/19 20:26:48
// Design Name: 
// Module Name: uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


/* UART transmit */

module uart_tx(
    input clk,
    input rst,
    input txd_start,    // 串口开始一次发送
    input [7:0] tx_data,

    output reg tx,
    output reg tx_done  // 一次串口发送完成的信号
    );

    parameter CLK_F = 100000000;
    parameter UART_B = 9600;
    parameter B_CNT = CLK_F / UART_B;

    reg txd_en;
    reg [1:0] txd_start_r;
    reg [15:0] baud_cnt = 16'b0;
    reg [3:0] bit_cnt = 4'b0;
    reg [7:0] tmp_data;

    always @(posedge clk) begin
        if (txd_start) 
            tmp_data <= tx_data;
        else 
            tmp_data <= tmp_data;
    end

    always @ (posedge clk or posedge rst) begin
        if (rst) 
            txd_en <= 1'b0;
        else begin
            if (txd_start) 
                txd_en <= 1'b1;
            else if ((bit_cnt == 4'd9) && (baud_cnt == B_CNT / 2)) 
                txd_en <= 1'b0;
            else 
                txd_en <= txd_en;
        end
    end
    
    always @ (posedge clk or negedge rst)
    begin
        if (rst)
            baud_cnt <= 16'd0;
        else if (txd_en)
        begin
            if (baud_cnt == B_CNT - 1)
                baud_cnt <= 16'd0;
            else
                baud_cnt <= baud_cnt + 1'b1;
        end
        else
            baud_cnt <= 16'd0;
    end

    always @ (posedge clk or negedge rst)
    begin
        if (rst)
            bit_cnt <= 4'd0;
        else if (txd_en)
        begin
            if (baud_cnt == B_CNT - 1) 
                bit_cnt <= bit_cnt + 1'b1;
            else
                bit_cnt <= bit_cnt;
        end
        else
            bit_cnt <= 4'd0;
    end

    always @ (posedge clk or posedge rst) begin
        if (rst) 
            tx <= 1'b1;
        else if (txd_en) begin
            case (bit_cnt) 
                4'd0: tx <= 1'b0;
                4'd1: tx <= tmp_data[0];
                4'd2: tx <= tmp_data[1];
                4'd3: tx <= tmp_data[2];
                4'd4: tx <= tmp_data[3];
                4'd5: tx <= tmp_data[4];
                4'd6: tx <= tmp_data[5];
                4'd7: tx <= tmp_data[6];
                4'd8: tx <= tmp_data[7];
                4'd9: tx <= 1'b1;
                default: tx <= 1'b1;
            endcase
        end
        else 
            tx <= 1'b1;
    end

    always @ (posedge clk) begin 
        if ((bit_cnt == 4'd9) && (baud_cnt == B_CNT / 2)) 
            tx_done <= 1'b1;
        else 
            tx_done <= 1'b0;
    end

endmodule
